/*
 * The MIT License
 *
 * Copyright 2012 http://generic-toolset.googlecode.com.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.rlpw.util;

import java.util.ArrayList;
import java.util.Collection;

/**
 * A simple extension of the <tt>ArrayList</tt>, which holds a maximum of one
 * item per reference.
 *
 * @param <T> the type of the elements
 * @see java.util.ArrayList
 */
public class UniqueList<T> extends ArrayList<T> {

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public UniqueList() {
        this(10);
    }

    /**
     * Constructs an empty list with the specified initial capacity.
     *
     * @param initialCapacity the initial capacity of the list
     * @exception IllegalArgumentException if the specified initial capacity is
     * negative
     */
    public UniqueList(int initialCapacity) {
        super(initialCapacity);
    }

    /**
     * Constructs a unique list containing the elements of the specified
     * collection, in the order they are returned by the collection's iterator.
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public UniqueList(Collection<? extends T> c) {
        addAll(c);
    }

    /**
     * If not yet contained the specified element then appends the specified
     * element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> if the item has been added
     */
    @Override
    public boolean add(T e) {
        if (!contains(e)) {
            return super.add(e);
        } else {
            return false;
        }
    }

    /**
     * Appends all unique elements in the specified collection to the end of
     * this list, in the order that they are returned by the specified
     * collection's Iterator. The behavior of this operation is undefined if the
     * specified collection is modified while the operation is in progress.
     * (This implies that the behavior of this call is undefined if the
     * specified collection is this list, and this list is nonempty.)
     *
     * @param c collection containing elements to be added to this list
     * @return <tt>true</tt> if this list changed as a result of the call
     * @throws NullPointerException if the specified collection is null
     */
    @Override
    public boolean addAll(Collection<? extends T> c) {

        boolean in = false;
        for (T obj : c) {
            in |= add(obj);
        }

        return in;
    }

    /**
     * Inserts all unique elements in the specified collection into this list,
     * starting at the specified position. Shifts the element currently at that
     * position (if any) and any subsequent elements to the right (increases
     * their indices). The new elements will appear in the list in the order
     * that they are returned by the specified collection's iterator.
     *
     * @param index index at which to insert the first element from the
     * specified collection
     * @param c collection containing elements to be added to this list
     * @return <tt>true</tt> if this list changed as a result of the call
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @throws NullPointerException if the specified collection is null
     */
    @Override
    public boolean addAll(int index, Collection<? extends T> c) {

        int ind = index;
        for (T obj : c) {
            if (!contains(obj)) {
                super.add(ind++, obj);
            }

        }
        return true;

    }

    /**
     * If not yet contained the specified element then inserts the specified
     * element at the specified position in this list. Shifts the element
     * currently at that position (if any) and any subsequent elements to the
     * right (adds one to their indices).
     *
     * @param index index at which the specified element is to be inserted
     * @param element element to be inserted
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    @Override
    public void add(int index, T element) {
        if (!contains(element)) {
            super.add(index, element);
        }
    }

    /**
     * If not yet contained the specified element then replaces the element at
     * the specified position in this list with the specified element.
     *
     * @param index index of the element to replace
     * @param element element to be stored at the specified position
     * @return the element previously at the specified position
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    @Override
    public T set(int index, T element) {
        if (!contains(element) || get(index).equals(element)) {
            return super.set(index, element);
        } else {
            return null;
        }
    }
}
